<?php

namespace App\Service;

use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Response;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Psr\Http\Message\ResponseInterface;

class ExcelService {
    private Worksheet $sheet;
    private Spreadsheet $spreadsheet;
    private $row;

    //构造函数 创建一个PhpSpreadsheet实例
    public function __construct() {
        // Create new Spreadsheet object
        $this->spreadsheet = new Spreadsheet();
        // Set document properties
        $this->spreadsheet->getProperties()->setCreator('Maarten Balliauw')
            ->setLastModifiedBy('Maarten Balliauw')
            ->setTitle('Office 2007 XLSX Test Document')
            ->setSubject('Office 2007 XLSX Test Document')
            ->setDescription('Test document for Office 2007 XLSX, generated using PHP classes.')
            ->setKeywords('office 2007 openxml php')
            ->setCategory('Test result file');
        // Add some data
        $this->spreadsheet->setActiveSheetIndex(0);
        $this->sheet = $this->spreadsheet->getActiveSheet();
        // Rename worksheet
        $this->spreadsheet->getActiveSheet()->setTitle('Sheet1');
    }

    //设置表头
    public function setHeader($title): ExcelService {
        foreach ($title as $key => $item) {
            $this->sheet->setCellValue(chr($key + 65) . '1', $item);
        }
        $this->row = 2; // 从第二行开始
        return $this;
    }

    //添加表内容
    public function addData($data): ExcelService {
        foreach ($data as $item) {
            $dataCol = 'A';
            foreach ($item as $value) {
                // 单元格内容写入
                $this->sheet->setCellValue($dataCol . $this->row, $value);
                $dataCol++;
            }
            $this->row++;
        }
        return $this;
    }

    //保存到服务器本地
    public function saveToLocal($fileName): array {
        // Set active sheet index to the first sheet, so Excel opens this as the first sheet
        $this->spreadsheet->setActiveSheetIndex(0);

        $fileName = $fileName . '.xlsx';
        $url = '/storage/' . $fileName;
        $outFilename = BASE_PATH . $url;
        $writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
        $writer->save($outFilename);
        $this->spreadsheet->disconnectWorksheets();
        unset($this->spreadsheet);
        return ['path' => $outFilename, 'filename' => $fileName];
    }

    //直接从浏览器下载到本地，有问题，不使用
    // php://output 目前PhpSpreadsheet插件有问题，PhpSpreadsheet插件作者还在修复
    public function saveToBrowser($fileName) {
        $fileName = $fileName . '.xlsx';
        //xls='application/vnd.ms-excel'
        //xlsx='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

        $writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $fileName . '"');
        header('Cache-Control: max-age=0');

        return $writer->save('php://output');
    }

    //保存临时文件在从浏览器自动下载到本地
    public function saveToBrowserByTmp($fileName): ResponseInterface {
        $fileName = $fileName . '.xlsx';

        $writer = IOFactory::createWriter($this->spreadsheet, "Xlsx");
        //保存到服务器的临时文件下
        $writer->save("./tmp.xlsx");

        //将文件转字符串
        $content = file_get_contents('./tmp.xlsx');

        //删除临时文件
        unlink("./tmp.xlsx");

        $response = new Response();
        //xls='application/vnd.ms-excel'
        //xlsx='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        $contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

        return $response->withHeader('content-description', 'File Transfer')
            ->withHeader('content-type', $contentType)
            ->withHeader('content-disposition', "attachment; filename={$fileName}")
            ->withHeader('content-transfer-encoding', 'binary')
            ->withHeader('pragma', 'public')
            ->withBody(new SwooleStream((string)$content));
    }
}